package com.wnxy.admin.controller;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageInfo;
import com.wnxy.admin.common.ResponseResult;
import com.wnxy.admin.common.handler.*;
import com.wnxy.admin.common.util.OrderUtil;
import com.wnxy.admin.common.util.TokenUtil;
import com.wnxy.admin.config.MessageQueueConfig;
import com.wnxy.admin.dto.ReservationChargingPileDto;
import com.wnxy.admin.dto.ReservationChargingStationDto;
import com.wnxy.admin.dto.ReservationDto;
import com.wnxy.admin.entity.ChargingPile;
import com.wnxy.admin.entity.Order;
import com.wnxy.admin.entity.Reservation;
import com.wnxy.admin.service.IChargingPileService;
import com.wnxy.admin.service.IChargingStationService;
import com.wnxy.admin.service.ICustomerService;
import com.wnxy.admin.service.IReservationService;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 预约表 前端控制器
 * </p>
 *
 * @author LQC
 * @since 2023-11-29
 */
@RestController
@RequestMapping("/reservation")
public class ReservationController {

    private final IReservationService reservationServiceImpl;
    private final RabbitTemplate rabbitTemplate;
    private final OrderUtil orderUtil;
    private final IChargingPileService chargingPileServiceImpl;
    private final IChargingStationService chargingStationServiceImpl;
    private final ICustomerService customerServiceImpl;


    public ReservationController(IReservationService reservationServiceImpl, RabbitTemplate rabbitTemplate, OrderUtil orderUtil, IChargingPileService chargingPileServiceImpl, IChargingStationService chargingStationServiceImpl, ICustomerService customerServiceImpl) {
        this.reservationServiceImpl = reservationServiceImpl;
        this.rabbitTemplate = rabbitTemplate;
        this.orderUtil = orderUtil;
        this.chargingPileServiceImpl = chargingPileServiceImpl;
        this.chargingStationServiceImpl = chargingStationServiceImpl;
        this.customerServiceImpl = customerServiceImpl;
    }

    @GetMapping("/getStationAndPiles")
    public ResponseResult getStationAndPiles() {
        List<ReservationChargingStationDto> chargingStations = chargingStationServiceImpl.getAllChargingStationsWithPiles();
        List<ReservationChargingPileDto> allPiles = chargingPileServiceImpl.getAllFromReservation();

        // 将充电桩按照电站ID进行分组
        Map<Integer, List<ReservationChargingPileDto>> pilesByStationId = allPiles.stream()
                .collect(Collectors.groupingBy(ReservationChargingPileDto::getChargingStationId));

        // 将分组后的充电桩列表设置到对应的电站对象中
        chargingStations.forEach(station -> station.setPiles(pilesByStationId.getOrDefault(station.getId(),
                Collections.emptyList())));

        return ResponseResult.ok(chargingStations);
    }

    //获取所选电站的充电桩
    @GetMapping("/findByStation")
    public ResponseResult findByStation(Integer chargingStationId) {
        if (null == chargingStationId) {
            List<ChargingPile> piles = chargingPileServiceImpl.list(Wrappers.lambdaQuery(ChargingPile.class)
                    .eq(ChargingPile::getChargingPileState, "空闲"));
            return ResponseResult.ok(piles);
        }
        List<ChargingPile> piles = chargingPileServiceImpl.list(Wrappers.lambdaQuery(ChargingPile.class)
                .eq(ChargingPile::getChargingStationId, chargingStationId)
                .eq(ChargingPile::getChargingPileState, "空闲"));
        return ResponseResult.ok(piles);
    }


//    //分页显示预约单,可根据订单号查询相关订单

    @GetMapping("/pageByOrderNum")
    public ResponseResult page(Integer pageNum,
                               Integer pageSize,
                               @RequestParam(required = false) String keyword) {
        PageInfo<ReservationDto> pageInfo = reservationServiceImpl.getAll(pageNum, pageSize, keyword);
        return ResponseResult.ok(pageInfo);
    }

    @GetMapping("/pageByOrderNumByCustomerId")
    public ResponseResult pageByOrderNumByCustomerId(Integer pageNum,
                               Integer pageSize,
                               @RequestParam(required = false) String keyword,@RequestHeader("Authorization") String token) {
        Asserts.fail(!StringUtils.hasLength(token), BusinessEnum.CARNUM_OR_CARVIM_IS_NUll);
        Integer staffId = Integer.valueOf(TokenUtil.getPayLoad(token.replace("Bearer", ""), "staffId"));
        PageInfo<ReservationDto> pageInfo = reservationServiceImpl.getByCustomerId(pageNum, pageSize, keyword,staffId);
        return ResponseResult.ok(pageInfo);
    }

    //删除预约操作
    @DeleteMapping("/remove/{id}")
    public ResponseResult remove(@PathVariable Integer id) {
        Reservation res = reservationServiceImpl.getById(id);
        if (res.getState() == 0) {
            return ResponseResult.fail(BusinessEnum.STATE_IS_RESERVATION);
        }
        reservationServiceImpl.update(Wrappers.lambdaUpdate(Reservation.class)
                .eq(Reservation::getId, id)
                .set(Reservation::getFlag, id));
        return ResponseResult.ok();
    }


    //取消预约操作
    @PostMapping("/cancellation")
    public ResponseResult cancellation(@RequestBody Reservation reservation) {
        reservationServiceImpl.update(Wrappers.lambdaUpdate(Reservation.class)
                .eq(Reservation::getId, reservation.getId())
                .set(Reservation::getState, ReservationEnum.CANCELED.getCode()));

        //修改客户状态
        customerServiceImpl.editService(reservation, 0);

        //修改电桩状态
        Long chargingId = Long.valueOf(reservation.getChargingId());
        chargingPileServiceImpl.updatePileStateById(chargingId, ChargingPileStateEnum.PIE_DEFAULT.getCode());

        return ResponseResult.ok();
    }

    //修改操作
    @PostMapping("edit")
    public ResponseResult edit(@RequestBody Reservation reservation) {
        if (!isReservation(reservation.getCustomerId(), reservation.getOrdernum())) {
            return ResponseResult.fail(BusinessEnum.RESERVATION_IS_RE);
        }
        if (reservation.getState() != 0){
            reservationServiceImpl.updateById(reservation);
            return ResponseResult.ok();
        }
        Reservation dbReservation = reservationServiceImpl.getById(reservation);
        if (!Objects.equals(dbReservation.getChargingId(), reservation.getChargingId())){
            Long dbChargingId = Long.valueOf(dbReservation.getChargingId());
            chargingPileServiceImpl.updatePileStateById(dbChargingId, ChargingPileStateEnum.PIE_DEFAULT.getCode());
            Long chargingId = Long.valueOf(reservation.getChargingId());
            chargingPileServiceImpl.updatePileStateById(chargingId, ChargingPileStateEnum.PIE_RESERVATION.getCode());
        }


        reservationServiceImpl.updateById(reservation);
        return ResponseResult.ok();
    }


    //添加预约操作
    @PostMapping("add")
    public ResponseResult add(@RequestBody Reservation reservation, @RequestHeader("Authorization") String token) {
        if (reservation.getState() != ReservationEnum.APPOINTMENT_IN_PROGRESS.getCode()) {
            reservationServiceImpl.save(reservation);
            return ResponseResult.ok();
        }
        Asserts.fail(!StringUtils.hasLength(token), BusinessEnum.CARNUM_OR_CARVIM_IS_NUll);
        Integer staffId = Integer.valueOf(TokenUtil.getPayLoad(token.replace("Bearer", ""), "staffId"));
        reservation = isCustomer(reservation, staffId);
        try {
            List<Order> orders = orderUtil.queryNotOkOrderByCustomerId(reservation.getCustomerId());
            if (orders.size() > 1) {
                return ResponseResult.fail(BusinessEnum.ORDER_UNPAID_OR_NOT_COMPLETED);
            }
            Snowflake snowflake = IdUtil.getSnowflake(5, 5);
            Long orderId = snowflake.nextId();

            if (!isReservation(reservation.getCustomerId(), orderId)) {
                return ResponseResult.fail(BusinessEnum.RESERVATION_IS_RE);
            }
            reservation.setOrdernum(orderId);

            LocalDateTime localDateTime = LocalDateTime.now();
            Date date = Date.from(localDateTime.toInstant(ZoneId.systemDefault().getRules().getOffset(localDateTime)));
            reservation.setStartTime(date);

            // 修改电桩状态
            Long chargingId = Long.valueOf(reservation.getChargingId());
            chargingPileServiceImpl.updatePileStateById(chargingId, ChargingPileStateEnum.PIE_RESERVATION.getCode());

            //  修改客户状态
            customerServiceImpl.editService(reservation, 1);

            // 计算延迟时间（假设传入的 endTime 是分钟数，转换成毫秒）
            long expirationTime = Long.parseLong(reservation.getEndTime()) * 60000;

            // 发送消息到延迟交换机
            sendDelayMessage(orderId, expirationTime);

            reservationServiceImpl.save(reservation);
            return ResponseResult.ok();
        } catch (Exception e) {
            // 处理异常，记录日志等
            e.printStackTrace();
            return ResponseResult.fail(SysBusinessEnum.SYSTEM_BUSY);
        }
    }

    /**
     * @note 判断是否为客户自行添加的预约信息
     */
    private Reservation isCustomer(Reservation reservation, Integer staffId) {
        if (null == reservation.getCustomerId()) {
            reservation.setCustomerId(staffId);
            return reservation;
        }
        return reservation;
    }

    /**
     * @note 判断该客户id是否存在状态为为预约中的预约单
     */
    private Boolean isReservation(Integer customerId, Long ordernum) {
        List<Reservation> reservations = reservationServiceImpl.list(Wrappers.lambdaQuery(Reservation.class)
                .eq(Reservation::getCustomerId, customerId));


        for (Reservation reservation : reservations) {
            boolean equals = !reservation.getOrdernum().equals(ordernum);
            if (reservation.getState() == ReservationEnum.APPOINTMENT_IN_PROGRESS.getCode() && equals) {
                return false;
            }
        }

        return true;
    }

    private void sendDelayMessage(Long orderId, long expirationTime) {
        try {
            // 发送消息到延迟交换机
            rabbitTemplate.convertAndSend(MessageQueueConfig.DELAY_SWITCH, MessageQueueConfig.RES_ROUTING_KEY,
                    orderId, message -> {
                        // 设置消息的延迟时间
                        message.getMessageProperties().setHeader("x-delay", expirationTime);
                        return message;
                    });
        } catch (AmqpException e) {
            // 处理消息发送异常
            e.printStackTrace();
        }
    }
}
